package com.semidata.trp.business.data;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import org.apache.ibatis.session.SqlSession;

import com.semidata.rtd.core.log.Logger;
import com.semidata.rtd.core.service.ServiceManager;
import com.semidata.trp.business.model.AlgorithmModel;
import com.semidata.trp.business.model.AllocationModel;
import com.semidata.trp.business.model.FixedCostModel;
import com.semidata.trp.business.model.MaterialModel;
import com.semidata.trp.business.model.MaterialTypeModel;
import com.semidata.trp.business.model.MaterialWeightModel;
import com.semidata.trp.business.model.OrganizationModel;
import com.semidata.trp.business.model.PositionModel;
import com.semidata.trp.business.model.ResourceModel;
import com.semidata.trp.business.model.ResourcePriceModel;
import com.semidata.trp.business.model.StrategyModel;
import com.semidata.trp.business.model.TrafficModel;
import com.semidata.trp.business.report.KeyWord;
import com.semidata.trp.business.report.ReportService;
import com.semidata.trp.business.report.Summary;
import com.semidata.trp.business.utils.SessionUtils;
import com.semidata.trp.business.utils.Utils;
import com.semidata.trp.message.business.Business;
import com.semidata.trp.message.business.Business.BudgetOrganization;
import com.semidata.trp.message.business.Business.BudgetStrategy;
import com.semidata.trp.message.business.Business.Resource.Builder;

public class BusinessData {

	private Map<Integer, MaterialModel> materials = new HashMap<>();
	private Map<Integer, OrganizationModel> organizations = new HashMap<>();
	private Map<Integer, ResourceModel> resources = new HashMap<>();
	private Map<Integer, PositionModel> positions = new HashMap<>();
	private Map<Integer, TrafficModel> traffics = new HashMap<>();
	private Map<Integer, StrategyModel> strategies = new HashMap<>();
	private Map<Integer, AlgorithmModel> algorithms = new HashMap<>();

	private Set<Integer> organizationCandidates = new HashSet<>();
	private Set<Integer> strategyCandidates = new HashSet<>();
	private Map<Integer, List<Business.KeyWord>> strategyKeywords = new HashMap<>();
	private Map<Integer,FixedCostModel> costs = new HashMap<>();
	
	private DataLoader loader;
	private long lastUpdate = 0;

	private static final int TYPE_SMOOTH = 1;

	public BusinessData(DataLoader loader) {
		this.loader = loader;
	}

	public boolean load() {

		boolean ret = false;

		try {
			SqlSession session = SessionUtils.getSession();

			List<MaterialModel> materialList = loader.loadMaterials(session);
			List<OrganizationModel> organizationList = loader
					.loadOrganizations(session);
			Map<Integer,FixedCostModel> costs = loader.loadFixedCost(session);
			List<PositionModel> positionList = loader.loadPositions(session);
			List<TrafficModel> trafficList = loader.loadTraffics(session);
			List<ResourceModel> resourceList = loader.loadResources(session);
			List<StrategyModel> strategyList = loader.loadStrategies(session);
			List<AlgorithmModel> algorithmList = loader.loadAlgorithms(session);
			List<Integer> strategyIds = new ArrayList<>();
			Map<Integer,Double> changeCost = new HashMap<>();
			for (StrategyModel model : strategyList)
				strategyIds.add(model.getId());
			Map<Integer, List<Business.KeyWord>> strategyKeywords = loader
					.loadStrategyHotword(session, strategyIds);
			SessionUtils.close(session);

			if (!materialList.isEmpty()) {
				ret = true;
				Logger.log("INFO", "update material");
				updateMaterials(materialList);
			}

			if (!organizationList.isEmpty()) {
				ret = true;
				Logger.log("INFO", "update organization");
				updateOrganizations(organizationList);
			}
			Set<Integer> changedCostId = new HashSet<>();
			if (!costs.isEmpty()) {
				ret = true;
				Logger.log("INFO", "update organization fixed cost");
				changedCostId.addAll(costs.keySet());
				updateFixedCosts(costs,changeCost);
			}
			
			if (!costs.isEmpty() || !organizationList.isEmpty()) {
				Set<Integer> orgIds = new HashSet<>();
				for (OrganizationModel org : organizationList)
					orgIds.add(org.getId());
				updateOrgCost(orgIds,changedCostId, changeCost);
			}
			if (!positionList.isEmpty()) {
				ret = true;
				Logger.log("INFO", "update position");
				updatePositions(positionList);
			}

			if (!trafficList.isEmpty()) {
				ret = true;
				Logger.log("INFO", "update traffic");
				updateTraffics(trafficList);
			}

			if (!resourceList.isEmpty()) {
				ret = true;
				Logger.log("INFO", "update resource");
				updateResources(resourceList);
			}

			if (!strategyList.isEmpty()) {
				ret = true;
				Logger.log("INFO", "update strategy");
				updateStrategies(strategyList);
			}

			if (strategyKeywords != null) {
				ret = true;
				Logger.log("INFO", "update strategy hot word");
				updateKeyword(strategyKeywords);
			}

			if (!algorithmList.isEmpty()) {
				ret = true;
				Logger.log("INFO", "update algorithm");
				updateAlgorithms(algorithmList);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		if (ret)
			lastUpdate = System.currentTimeMillis();

		return ret;
	}

	private void updateAlgorithms(List<AlgorithmModel> list) {
		// TODO Auto-generated method stub
		for(AlgorithmModel model : list){
				this.algorithms.put(model.getId(), model);
		}
	}

	public long getLastUpdate() {
		return lastUpdate;
	}

	private void updateMaterials(List<MaterialModel> list) {
		for (MaterialModel model : list) {
			if (model.isDeleted())
				materials.remove(model.getId());
			else
				materials.put(model.getId(), model);
		}
	}

	private void updateOrganizations(List<OrganizationModel> list) {
		for (OrganizationModel model : list) {
			if (model.isDeleted())
				organizations.remove(model.getId());
			else
				organizations.put(model.getId(), model);
		}
	}
	
	private void updateFixedCosts(Map<Integer,FixedCostModel> costs, Map<Integer,Double> change) {
		for (Map.Entry<Integer, FixedCostModel> fcost : costs.entrySet()) {
				Integer id = fcost.getKey();
				FixedCostModel fcm = fcost.getValue();
				if (this.costs.containsKey(id)) {
					FixedCostModel cost = this.costs.get(id);
					Double oldBalance = cost.getBalance();
					Double newBalance = fcm.getBalance();
					Double changeCost = 0.0;
					if(fcm.getDeleted() != 1) {
						changeCost = newBalance - oldBalance;
					} else {
						changeCost = 0.0 - newBalance;
					}
					change.put(id, changeCost);
				} 
				this.costs.put(id, fcm);

		}
		
	}
	
	private void updateOrgCost(Set<Integer> orgIds, Set<Integer> ids, Map<Integer,Double> change) {
		for(Map.Entry<Integer, FixedCostModel> fixedCost : this.costs.entrySet()){
			FixedCostModel typeCost = fixedCost.getValue();
			Integer id = fixedCost.getKey();
			Integer orgId = typeCost.getOrgId();
			Integer type = typeCost.getType();
			Integer deleted = typeCost.getDeleted();
			Double balance = typeCost.getBalance();
			if (orgIds.contains(orgId) && this.organizations.containsKey(orgId)){
				OrganizationModel org = this.organizations.get(orgId);
				if(type == 0) {
					if (deleted != 1)
						org.setInBalance(org.getInBalance() - balance);
				} else if (type == 1) {
					if (deleted != 1)
						org.setOutBalance(org.getOutBalance() - balance);
				} else if (type == 2) {
					if (deleted != 1)
						org.setAllyBalance(org.getAllyBalance() - balance);
				}
			} 
			if (!orgIds.contains(orgId) && ids.contains(id) && this.organizations.containsKey(orgId)) {
				OrganizationModel org = this.organizations.get(orgId);
				if (change.containsKey(id))
					balance = change.get(id);
				if(type == 0) {
					org.setInBalance(org.getInBalance() - balance);
				} else if (type == 1) {
					org.setOutBalance(org.getOutBalance() - balance);
				} else if (type == 2) {
					org.setAllyBalance(org.getAllyBalance() - balance);
				}
			}
		}

	}
	
	

	private void updatePositions(List<PositionModel> list) {
		for (PositionModel model : list) {
			if (model.isDeleted())
				positions.remove(model.getId());
			else
				positions.put(model.getId(), model);
		}
	}

	private void updateTraffics(List<TrafficModel> list) {
		for (TrafficModel model : list) {

			if (model.isDeleted())
				traffics.remove(model.getId());
			else
				traffics.put(model.getId(), model);
		}
	}

	private void updateResources(List<ResourceModel> list) {
		for (ResourceModel model : list) {
			if (model.isDeleted())
				resources.remove(model.getId());
			else
				resources.put(model.getId(), model);
		}
	}

	private void updateStrategies(List<StrategyModel> list) {
		for (StrategyModel model : list) {
			if (model.isDeleted()) {
				strategies.remove(model.getId());
				
			}else
				strategies.put(model.getId(), model);
		}
	}

	private void updateKeyword(Map<Integer, List<Business.KeyWord>> list) {
		for (Map.Entry<Integer, List<Business.KeyWord>> model : list.entrySet()) {
			Integer strategyId = model.getKey();
			List<Business.KeyWord> keywords = model.getValue();
			this.strategyKeywords.put(strategyId, keywords);
		}
	}

	private boolean isValidMaterial(int id) {
		MaterialModel material = materials.get(id);
		if (material == null)
			return false;
		if (material.isDeleted()) {
			Logger.log("DEBUG", "material must not be deleted");
			return false;
		}
		if (material.getLandingPage() == null
				|| material.getLandingPage().isEmpty()) {
			Logger.log("DEBUG", "material " + material.getId()
					+ ": landingpage is empty");
			return false;
		}
		if (material.getUrl() == null || material.getUrl().isEmpty()) {
			Logger.log("DEBUG", "material " + material.getId()
					+ ": url is empty");
			return false;
		}
		if (material.getStatus() != 1) {
			Logger.log("DEBUG", "material " + material.getId()
					+ ":  is not pass audit");
			return false;
		}
		return true;

	}

	private boolean isValidOrganization(int id) {
		OrganizationModel org = organizations.get(id);
		if (org == null)
			return false;
		if (org.isDeleted()) {
			Logger.log("DEBUG", "org must not be deleted");
			return false;
		}

		return true;

	}

	private boolean isValidResource(int id, long today) {
		ResourceModel resource = resources.get(id);
		if (resource == null)
			return false;
		if (resource.isDeleted()) {
			Logger.log("DEBUG", "resource must not be deleted");
			return false;
		}

		long start = Utils.getDate(resource.getStart().getTime());
		long end = Utils.getDate(resource.getEnd().getTime());

		if (today < start || today > end) {
			Logger.log("DEBUG", "resource " + resource.getId()
					+ " is not today");
			return false;
		}

		TrafficModel traffic = traffics.get(resource.getTrafficId());
		if (traffic == null || !traffic.isActive()) {
			Logger.log("DEBUG", "traffic " + resource.getId()
					+ " is not active");
			return false;
		}

		start = Utils.getDate(traffic.getStart().getTime());
		end = Utils.getDate(traffic.getEnd().getTime());

		if (today < start || today > end) {
			Logger.log("DEBUG", "traffic" + traffic.getId() + " is not today");
			return false;
		}
		return true;
	}

	private boolean isValidStrategy(StrategyModel strategy, long today) {

		if (strategy.isDeleted()) {
			Logger.log("DEBUG", "strategy must not be deleted");
			return false;
		}

		long start = Utils.getDate(strategy.getStart().getTime());
		long end = Utils.getDate(strategy.getEnd().getTime());

		if (today < start || today > end) {
			Logger.log("DEBUG", "strategy " + strategy.getId()
					+ " is not today");
			return false;
		}
		return true;
	}

	public Business.BusinessData getBusinessData() {

		long s = System.currentTimeMillis();
		long today = Utils.getDate(System.currentTimeMillis());

		Set<Integer> materialIds = new HashSet<>();
		Set<Integer> resourceIds = new HashSet<>();
		Set<Integer> positionIds = new HashSet<>();
		organizationCandidates = new HashSet<>();
		strategyCandidates = new HashSet<>();

		Business.BusinessData.Builder businessDataBuilder = Business.BusinessData
				.newBuilder();

		for (Map.Entry<Integer, StrategyModel> entry : strategies.entrySet()) {
			StrategyModel strategy = entry.getValue();
			if (!isValidStrategy(strategy, today))
				continue;
			if (!isValidOrganization(strategy.getOrgId()))
				continue;
			Business.Strategy.Builder strategyBuilder = Business.Strategy
					.newBuilder();
			strategyBuilder.setId(strategy.getId());
			strategyBuilder.setOrgId(strategy.getOrgId());
			strategyBuilder.setPriority(strategy.getPriority());
			strategyBuilder.setFrequency(strategy.getFrequency());
			strategyBuilder.setDailyBudgetIn(strategy.getDailyBudgetIn());
			strategyBuilder.setDailyBudgetOut(strategy.getDailyBudgetOut());
			strategyBuilder.setDailyBudgetAlly(strategy.getDailyBudgetAlly());
			strategyBuilder.setTotalBudgetIn(strategy.getTotalBudgetIn());
			strategyBuilder.setTotalBudgetOut(strategy.getTotalBudgetOut());
			strategyBuilder.setTotalBudgetAlly(strategy.getTotalBudgetAlly());
			strategyBuilder
					.setLandingPage(strategy.getLandingPage() == null ? ""
							: strategy.getLandingPage());
			if (strategyKeywords.containsKey(strategy.getId())) {
				strategyBuilder.addAllKeywords(strategyKeywords.get(strategy
						.getId()));
			} else {
				strategyBuilder
						.addAllKeywords(new ArrayList<Business.KeyWord>());
			}
			Map<Integer, ResourcePriceModel> resourcePrices = strategy
					.getResourcePrices();

			OrganizationModel org = organizations.get(strategy.getOrgId());
			for (ResourcePriceModel item : resourcePrices.values()) {
				if (!isValidResource(item.getResourceId(), today))
					continue;
				double price = 0;

				if (org.getType() != 0) {
					price = item.getPrice();

					ResourceModel resource = resources
							.get(item.getResourceId());
					Map<Integer, AllocationModel> allocations = resource
							.getAllocations();
					AllocationModel allocation = allocations.get(strategy
							.getOrgId());
					if (allocation == null && !resource.isAllowShared()
							&& strategy.getPriority() >= 0) {
						continue;
					}

					if (allocation != null) {
						if (allocation.getType() == 0) { // CPD
							price = 0;
						} else {
							price = allocation.getPrice();
						}
					}
				}

				resourceIds.add(item.getResourceId());

				Business.Strategy.ResourcePrice.Builder resourcePriceBuilder = Business.Strategy.ResourcePrice
						.newBuilder();
				resourcePriceBuilder.setResourceId(item.getResourceId());
				resourcePriceBuilder.setPrice(price);
				strategyBuilder.addResourcePrices(resourcePriceBuilder.build());

			}

			Map<Integer, MaterialWeightModel> materialWeights = strategy
					.getMaterialWeights();
			for (MaterialWeightModel item : materialWeights.values()) {
				if (!isValidMaterial(item.getMaterialId()))
					continue;
				materialIds.add(item.getMaterialId());
				Business.Strategy.MaterialWeight.Builder materialWeightBuilder = Business.Strategy.MaterialWeight
						.newBuilder();
				materialWeightBuilder.setMaterialId(item.getMaterialId());
				materialWeightBuilder.setWeight(item.getWeight());
				strategyBuilder.addMaterialWeights(materialWeightBuilder
						.build());
			}

			Set<String> areas = strategy.getAreas();
			for (String area : areas) {
				strategyBuilder.addAreas(area);
			}

			Set<Integer> hours = strategy.getHours();
			for (int hour : hours) {
				strategyBuilder.addHours(hour);
			}
			
			if(strategy.getAlgorithm() != null){
				strategyBuilder.setAlgorithmId(strategy.getAlgorithm());
			}else {
				strategyBuilder.setAlgorithmId(0);
			}
			
			if(strategy.getParams() != null){
				strategyBuilder.setParams(strategy.getParams());
			}else {
				strategyBuilder.setParams("");
			}			

			businessDataBuilder.addStrategies(strategyBuilder.build());
			organizationCandidates.add(strategy.getOrgId());
			strategyCandidates.add(strategy.getId());
		}

		for (int id : resourceIds) {

			ResourceModel resource = resources.get(id);
			TrafficModel traffic = traffics.get(resource.getTrafficId());
			if (positions.get(traffic.getPositionId()) == null) {
				continue;
			}
			
			positionIds.add(traffic.getPositionId());
			Builder resourceBuilder = Business.Resource.newBuilder();
			resourceBuilder.setId(id);
			resourceBuilder.setPositionId(traffic.getPositionId());
			resourceBuilder.setAllowShared(resource.isAllowShared());
			Set<String> areas = resource.getAreas();
			resourceBuilder.addAllAreas(areas);
			Set<Integer> hours = resource.getHours();
			resourceBuilder.addAllHours(hours);
			resourceBuilder.setFloor(resource.getFloor());
			businessDataBuilder.addResources(resourceBuilder.build());
		}

		for (int id : positionIds) {
			PositionModel position = positions.get(id);
			Business.Position.Builder positionBuilder = Business.Position
					.newBuilder();
			positionBuilder.setId(position.getId());
			if (position.getShowType() == 2){
				int height = 0;
				int width = 0;
				if(position.getArrangeType() == 0) {
					height = position.getHeight();
					width = position.getWidth() / position.getMax();
				} else if(position.getArrangeType() == 1){
					width = position.getWidth();
					height = position.getHeight() / position.getMax();
				} else {
					width = position.getWidth();
					height = position.getHeight();
				}
				positionBuilder.setWidth(width);
				positionBuilder.setHeight(height);
			} else {
				positionBuilder.setWidth(position.getWidth());
				positionBuilder.setHeight(position.getHeight());
			}
			
			positionBuilder.setSize(position.getSize());
			positionBuilder.setMin(position.getMin());
			positionBuilder.setMax(position.getMax());
			positionBuilder.setMediaType(position.getMediaType());
			for (MaterialTypeModel type : position.getTypes()) {
				positionBuilder.addType(type.getType());
			}
			businessDataBuilder.addPositions(positionBuilder.build());
		}

		for (int id : materialIds) {
			MaterialModel material = materials.get(id);

			Business.Material.Builder materialBuilder = Business.Material
					.newBuilder();

			materialBuilder.setId(material.getId());
			materialBuilder.setUrl(material.getUrl());
			materialBuilder.setWidth(material.getWidth());
			materialBuilder.setHeight(material.getHeight());
			materialBuilder.setSize(material.getSize());
			materialBuilder.setType(material.getType());
			materialBuilder.setLandingPage(material.getLandingPage());
			materialBuilder.setFrequency(material.getFrequency());
			businessDataBuilder.addMaterials(materialBuilder.build());
		}

		for (Map.Entry<Integer, AlgorithmModel> entry : algorithms.entrySet()) {
			AlgorithmModel algorithm = entry.getValue();
			Business.Algorithm.Builder algorithmBuilder = Business.Algorithm.newBuilder();
			algorithmBuilder.setId(algorithm.getId());
			if(algorithm.getCode() != null){
				algorithmBuilder.setCode(algorithm.getCode());
			}else {
				algorithmBuilder.setCode("");
			}
			businessDataBuilder.addAlgorithms(algorithmBuilder.build());
		}
		

		Business.BusinessData data = businessDataBuilder.build();
		return data;
	}

	public Business.BudgetData getBudgetData() {
		ReportService reportService = ServiceManager
				.getService(ReportService.class);

		Summary currentSummary = new Summary(reportService.getCurrentData()
				.getMonitorReportData());
		Summary baseSummary = new Summary(reportService.getBaseData()
				.getMonitorReportData());

		Business.BudgetData.Builder builder = Business.BudgetData.newBuilder();

		// Logger.log("DEBUG", "organizationCandidates:" +
		// organizationCandidates.toString());

		for (int id : organizationCandidates) {

			OrganizationModel org = organizations.get(id);
			if (org == null)
				continue;

			BudgetOrganization.Builder orgBuilder = Business.BudgetOrganization
					.newBuilder();
			orgBuilder.setId(id);
			orgBuilder.setIn(1);
			orgBuilder.setOut(1);
			orgBuilder.setAlly(1);	
			if(org.getType() != 0){
				
				if(org.getInBalance() <= 0){
					orgBuilder.setIn(0);
				}
				if(org.getOutBalance() <= 0){
					orgBuilder.setOut(0);
				}
				if(org.getAllyBalance() <= 0){
					orgBuilder.setAlly(0);
				}				
			}
			if (currentSummary.getOrganizationCosts().get(id) != null) {
				if (org.getType() != 0) {
					Double cost = currentSummary.getOrganizationCosts().get(id)
							.get(0);
					if (cost == null)
						cost = 0.0;
					if (org.getInBalance() <= cost) {
						orgBuilder.setIn(0);
					}
					cost = currentSummary.getOrganizationCosts().get(id).get(1);
					if (cost == null)
						cost = 0.0;
					if (org.getOutBalance() <= cost) {
						orgBuilder.setOut(0);
					}
					cost = currentSummary.getOrganizationCosts().get(id).get(2);
					if (cost == null)
						cost = 0.0;
					if (org.getAllyBalance() <= cost) {
						orgBuilder.setAlly(0);
					}
				}
			}
			builder.addOrganizations(orgBuilder.build());
			/*
			 * Double cost = currentSummary.getOrganizationCosts().get(id); if
			 * (cost == null) cost = 0.0; if (balance > cost || org.getType() ==
			 * 0) builder.addOrganizations(id);
			 */
		}

		for (int id : strategyCandidates) {
			StrategyModel strategy = strategies.get(id);
			if (strategy == null)
				continue;
			Double currentCostIn = null;
			Double currentCostOut = null;
			Double currentCostAlly = null;
			Double baseCostIn = null;
			Double baseCostOut = null;
			Double baseCostAlly = null;
			Long currentImpressionIn = null;
			Long currentImpressionOut = null;
			Long currentImpressionAlly = null;
			Long baseImpressionIn = null;
			Long baseImpressionOut = null;
			Long baseImpressionAlly = null;

			boolean in = true, out = true, ally = true;
			/*
			if(strategy.getTotalBudgetIn() <= 0 || strategy.getTotalAmountIn() <= 0){
				in = false;
			}

			if(strategy.getTotalBudgetOut() <= 0 || strategy.getTotalAmountOut() <= 0){
				out = false;
			}
			
			if(strategy.getTotalBudgetAlly() <= 0 || strategy.getTotalAmountAlly() <= 0){
				ally = false;
			}*/
			
			if (currentSummary.getStrategyCosts().get(id) != null) {
				currentCostIn = currentSummary.getStrategyCosts().get(id)
						.get(0);
				currentCostOut = currentSummary.getStrategyCosts().get(id)
						.get(1);
				currentCostAlly = currentSummary.getStrategyCosts().get(id)
						.get(2);
			}
			if (currentCostIn == null)
				currentCostIn = 0.0;
			if (currentCostOut == null)
				currentCostOut = 0.0;
			if (currentCostAlly == null)
				currentCostAlly = 0.0;
			if (baseSummary.getStrategyCosts().get(id) != null) {
				baseCostIn = baseSummary.getStrategyCosts().get(id).get(0);
				baseCostOut = baseSummary.getStrategyCosts().get(id).get(1);
				baseCostAlly = baseSummary.getStrategyCosts().get(id).get(2);
			}
			if (baseCostIn == null)
				baseCostIn = 0.0;
			if (baseCostOut == null)
				baseCostOut = 0.0;
			if (baseCostAlly == null)
				baseCostAlly = 0.0;
			if (currentSummary.getStrategyImpressions().get(id) != null) {
				currentImpressionIn = currentSummary.getStrategyImpressions()
						.get(id).get(0);
				currentImpressionOut = currentSummary.getStrategyImpressions()
						.get(id).get(1);
				currentImpressionAlly = currentSummary.getStrategyImpressions()
						.get(id).get(2);
			}
			if (currentImpressionIn == null)
				currentImpressionIn = 0L;
			if (currentImpressionOut == null)
				currentImpressionOut = 0L;
			if (currentImpressionAlly == null)
				currentImpressionAlly = 0L;
			if (baseSummary.getStrategyImpressions().get(id) != null) {
				baseImpressionIn = baseSummary.getStrategyImpressions().get(id)
						.get(0);
				baseImpressionOut = baseSummary.getStrategyImpressions()
						.get(id).get(1);
				baseImpressionAlly = baseSummary.getStrategyImpressions()
						.get(id).get(2);
			}
			if (baseImpressionIn == null)
				baseImpressionIn = 0L;
			if (baseImpressionOut == null)
				baseImpressionOut = 0L;
			if (baseImpressionAlly == null)
				baseImpressionAlly = 0L;

			BudgetStrategy.Builder straBuilder = BudgetStrategy.newBuilder();
			straBuilder.setId(id);
			// in
			if (strategy.getTotalBudgetIn() > 0
					&& currentCostIn >= strategy.getTotalBudgetIn()) {
				Logger.log("DEBUG", "strategy " + strategy.getId()
						+ ": total budgetIn is exceeded");
				in = false;
			}

			if (strategy.getTotalAmountIn() > 0
					&& currentImpressionIn >= strategy.getTotalAmountIn()) {
				Logger.log("DEBUG", "strategy " + strategy.getId()
						+ ": total amountIn is exceeded");
				in = false;
			}
			// out
			if (strategy.getTotalBudgetOut() > 0
					&& currentCostOut >= strategy.getTotalBudgetOut()) {
				Logger.log("DEBUG", "strategy " + strategy.getId()
						+ ": total budgetOut is exceeded");
				out = false;
			}

			if (strategy.getTotalAmountOut() > 0
					&& currentImpressionOut >= strategy.getTotalAmountOut()) {
				Logger.log("DEBUG", "strategy " + strategy.getId()
						+ ": total amountOut is exceeded");
				out = false;
			}
			// ally
			if (strategy.getTotalBudgetAlly() > 0
					&& currentCostAlly >= strategy.getTotalBudgetAlly()) {
				Logger.log("DEBUG", "strategy " + strategy.getId()
						+ ": total budgetAlly is exceeded");
				ally = false;
			}

			if (strategy.getTotalAmountAlly() > 0
					&& currentImpressionAlly >= strategy.getTotalAmountAlly()) {
				Logger.log("DEBUG", "strategy " + strategy.getId()
						+ ": total amountAlly is exceeded");
				ally = false;
			}

			double ratio = 1;

			TreeSet<Integer> set = new TreeSet<>(strategy.getHours());
			
			if (set.isEmpty()) {
				for (int i = 0; i < 24; i++) {
					set.add(i);
				}
			}
			Calendar calendar = Calendar.getInstance();
			int hour = calendar.get(Calendar.HOUR_OF_DAY);
			int n = 0;
			for (int h : set) {
				if (h < hour)
					n++;
				else
					break;
			}

			int sec = 0;
			if (set.contains(hour)) {
				sec = calendar.get(Calendar.MINUTE) * 60
						+ calendar.get(Calendar.SECOND);

			}

			ratio = ((double) (n * 3600 + sec)) / (set.size() * 3600.0);
			if (strategy.getConsumeTypeIn() == TYPE_SMOOTH) {
				if (strategy.getDailyBudgetIn() > 0) {
					if (currentCostIn - baseCostIn >= strategy
							.getDailyBudgetIn() * ratio) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily budgetIn is exceeded. ratio = "
								+ ratio);
						in = false;
					}

				}

				if (strategy.getDailyAmountIn() > 0) {
					if (currentImpressionIn - baseImpressionIn >= strategy
							.getDailyAmountIn() * ratio) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily amountIn is exceeded. ratio = "
								+ ratio);
						in = false;
					}
				}
			}else {
				if (strategy.getDailyBudgetIn() > 0) {

					if (currentCostIn - baseCostIn >= strategy
							.getDailyBudgetIn()) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily budgetIn is exceeded.");
						in = false;
					}

				}

				if (strategy.getDailyAmountIn() > 0) {
					if (currentImpressionIn - baseImpressionIn >= strategy
							.getDailyAmountIn()) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily amountIn is exceeded.");
						in = false;
					}
				}				
			}

			if (strategy.getConsumeTypeOut() == TYPE_SMOOTH) {
				if (strategy.getDailyBudgetOut() > 0) {

					if (currentCostOut - baseCostOut >= strategy
							.getDailyBudgetOut() * ratio) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily budgetOut is exceeded. ratio = "
								+ ratio);
						out = false;
					}

				}

				if (strategy.getDailyAmountOut() > 0) {
					if (currentImpressionOut - baseImpressionOut >= strategy
							.getDailyAmountOut() * ratio) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily amountOut is exceeded. ratio = "
								+ ratio);
						out = false;
					}
				}
			}else {
				if (strategy.getDailyBudgetOut() > 0) {

					if (currentCostOut - baseCostOut >= strategy
							.getDailyBudgetOut()) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily budgetOut is exceeded." );
						out = false;
					}

				}

				if (strategy.getDailyAmountOut() > 0) {
					if (currentImpressionOut - baseImpressionOut >= strategy
							.getDailyAmountOut()) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily amountOut is exceeded.");
						out = false;
					}
				}				
			}

			if (strategy.getConsumeTypeAlly() == TYPE_SMOOTH) {
				if (strategy.getDailyBudgetAlly() > 0) {

					if (currentCostAlly - baseCostAlly >= strategy
							.getDailyBudgetAlly() * ratio) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily budgetAlly is exceeded. ratio = "
								+ ratio);
						ally = false;
					}

				}

				if (strategy.getDailyAmountAlly() > 0) {
					if (currentImpressionAlly - baseImpressionAlly >= strategy
							.getDailyAmountAlly() * ratio) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily amountAlly is exceeded. ratio = "
								+ ratio);
						ally = false;
					}
				}
			}else {
				if (strategy.getDailyBudgetAlly() > 0) {

					if (currentCostAlly - baseCostAlly >= strategy
							.getDailyBudgetAlly()) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily budgetAlly is exceeded.");
						ally = false;
					}

				}

				if (strategy.getDailyAmountAlly() > 0) {
					if (currentImpressionAlly - baseImpressionAlly >= strategy
							.getDailyAmountAlly()) {
						Logger.log("DEBUG", "strategy " + strategy.getId()
								+ ": daily amountAlly is exceeded.");
						ally = false;
					}
				}
			}

			if (in) {
				straBuilder.setIn(1);
			} else {
				straBuilder.setIn(0);
			}
			if (out) {
				straBuilder.setOut(1);
			} else {
				straBuilder.setOut(0);
			}
			if (ally) {
				straBuilder.setAlly(1);
			} else {
				straBuilder.setAlly(0);
			}

			builder.addStrategies(straBuilder.build());
		}
		return builder.build();
	}
	/*
	 * private BudgetStrategy.Builder isActiveStrategy(int id, StrategyModel
	 * strategy, double totalCostIn, double todayCostIn, long totalPVIn, long
	 * todayPVIn, double totalCostOut, double todayCostOut, long totalPVOut,
	 * long todayPVOut, double totalCostAlly, double todayCostAlly, long
	 * totalPVAlly, long todayPVAlly) { BudgetStrategy.Builder straBuilder =
	 * BudgetStrategy.newBuilder(); straBuilder.setId(id); boolean in = true,
	 * out = true, ally = true; // in if (strategy.getTotalBudgetIn() > 0 &&
	 * totalCostIn >= strategy.getTotalBudgetIn()) { Logger.log("DEBUG",
	 * "strategy " + strategy.getId() + ": total budgetIn is exceeded"); in =
	 * false; }
	 * 
	 * if (strategy.getTotalAmountIn() > 0 && totalPVIn >=
	 * strategy.getTotalAmountIn()) { Logger.log("DEBUG", "strategy " +
	 * strategy.getId() + ": total amountIn is exceeded"); in = false; }
	 * 
	 * double ratio = 1;
	 * 
	 * if ((strategy.getDailyBudgetIn() > 0 || strategy.getDailyAmountIn() > 0)
	 * && strategy.getConsumeType() == TYPE_SMOOTH) { TreeSet<Integer> set = new
	 * TreeSet<>(strategy.getHours()); if (set.isEmpty()) { for (int i = 0; i <
	 * 24; i++) { set.add(i); } } Calendar calendar = Calendar.getInstance();
	 * int hour = calendar.get(Calendar.HOUR); int n = 0; for (int h : set) { if
	 * (h < hour) n++; else break; }
	 * 
	 * int sec = 0; if (set.contains(hour)) { sec =
	 * calendar.get(Calendar.MINUTE) * 60 + calendar.get(Calendar.SECOND);
	 * 
	 * }
	 * 
	 * ratio = ((double) (n * 3600 + sec)) / (set.size() * 3600.0); }
	 * 
	 * if (strategy.getDailyBudgetIn() > 0) {
	 * 
	 * if (todayCostIn >= strategy.getDailyBudgetIn() * ratio) {
	 * Logger.log("DEBUG", "strategy " + strategy.getId() +
	 * ": daily budgetIn is exceeded. ratio = " + ratio); in = false; }
	 * 
	 * }
	 * 
	 * if (strategy.getDailyAmountIn() > 0) { if (todayPVIn >=
	 * strategy.getDailyAmountIn() * ratio) { Logger.log("DEBUG", "strategy " +
	 * strategy.getId() + ": daily amountIn is exceeded. ratio = " + ratio); in
	 * = false; } } if (in) { straBuilder.setIn(1); } else {
	 * straBuilder.setIn(0); } // out if (strategy.getTotalBudgetOut() > 0 &&
	 * totalCostOut >= strategy.getTotalBudgetOut()) { Logger.log("DEBUG",
	 * "strategy " + strategy.getId() + ": total budgetOut is exceeded"); out =
	 * false; }
	 * 
	 * if (strategy.getTotalAmountOut() > 0 && totalPVOut >=
	 * strategy.getTotalAmountOut()) { Logger.log("DEBUG", "strategy " +
	 * strategy.getId() + ": total amountOut is exceeded"); out = false; }
	 * 
	 * if (strategy.getDailyBudgetOut() > 0) {
	 * 
	 * if (todayCostOut >= strategy.getDailyBudgetOut() * ratio) {
	 * Logger.log("DEBUG", "strategy " + strategy.getId() +
	 * ": daily budgetOut is exceeded. ratio = " + ratio); out = false; }
	 * 
	 * }
	 * 
	 * if (strategy.getDailyAmountOut() > 0) { if (todayPVIn >=
	 * strategy.getDailyAmountOut() * ratio) { Logger.log("DEBUG", "strategy " +
	 * strategy.getId() + ": daily amountOut is exceeded. ratio = " + ratio);
	 * out = false; } } if (out) { straBuilder.setOut(1); } else {
	 * straBuilder.setOut(0); } // ally if (strategy.getTotalBudgetAlly() > 0 &&
	 * totalCostAlly >= strategy.getTotalBudgetAlly()) { Logger.log("DEBUG",
	 * "strategy " + strategy.getId() + ": total budgetAlly is exceeded"); ally
	 * = false; }
	 * 
	 * if (strategy.getTotalAmountAlly() > 0 && totalPVAlly >=
	 * strategy.getTotalAmountAlly()) { Logger.log("DEBUG", "strategy " +
	 * strategy.getId() + ": total amountAlly is exceeded"); ally = false; }
	 * 
	 * if (strategy.getDailyBudgetAlly() > 0) {
	 * 
	 * if (todayCostAlly >= strategy.getDailyBudgetAlly() * ratio) {
	 * Logger.log("DEBUG", "strategy " + strategy.getId() +
	 * ": daily budgetAlly is exceeded. ratio = " + ratio); ally = false; }
	 * 
	 * }
	 * 
	 * if (strategy.getDailyAmountAlly() > 0) { if (todayPVAlly >=
	 * strategy.getDailyAmountAlly() * ratio) { Logger.log("DEBUG", "strategy "
	 * + strategy.getId() + ": daily amountAlly is exceeded. ratio = " + ratio);
	 * ally = false; } } if (ally) { straBuilder.setAlly(1); } else {
	 * straBuilder.setAlly(0); }
	 * 
	 * return straBuilder; }
	 */

}
